
//////////////////////////////////////////////////////////////////////////
//	TGA
//////////////////////////////////////////////////////////////////////////
#if KIMAGE_TGA
class KImageFormatTGA
{

};

#else 

/*
 */
class ImageFileTGA {
		
		ImageFileTGA();
		
	public:
		
		// info image
		static int info(Image &image,const char *name);
		
		// load image
		static int load(Image &image,const char *name);
		
		// save image
		static int save(const Image &image,const char *name);
		
	private:
		
		struct Header;
		
		static int read_header(Header &header,int &format,const File &file);
		
		static void read_data(unsigned char *data,const File &file,size_t size,int pixel_size,int compression);
		
		struct Header {
			unsigned char id_length;
			unsigned char colormap_type;
			unsigned char image_type;
			unsigned short colormap_index;
			unsigned short colormap_length;
			unsigned char colormap_size;
			unsigned short x_orign;
			unsigned short y_orign;
			unsigned short width;
			unsigned short height;
			unsigned char pixel_size;
			unsigned char attributes;
		};
};

/*
 */
ImageFileTGA::ImageFileTGA() {
	
}

/*
 */
int ImageFileTGA::read_header(Header &header,int &format,const File &file) {
	
	format = -1;
	memset(&header,0,sizeof(header));
	
	// read header
	header.id_length = file.readUChar();
	header.colormap_type = file.readUChar();
	header.image_type = file.readUChar();
	header.colormap_index = file.readUShort();
	header.colormap_length = file.readUShort();
	header.colormap_size = file.readUChar();
	header.x_orign = file.readUShort();
	header.y_orign = file.readUShort();
	header.width = file.readUShort();
	header.height = file.readUShort();
	header.pixel_size = file.readUChar();
	header.attributes = file.readUChar();
	
	// indexed image
	if(header.image_type == 1 || header.image_type == 9) {
		if(header.colormap_size == 24) format = Image::FORMAT_RGB8;
		else if(header.colormap_size == 32) format = Image::FORMAT_RGBA8;
		else {
			Log::error("ImageFileTGA::read_header(): unsupported colormap size %d in \"%s\" file\n",header.colormap_size,file.getName());
			return 0;
		}
	}
	// grayscale image
	else if(header.image_type == 3 || header.image_type == 11) {
		if(header.pixel_size == 8) format = Image::FORMAT_R8;
		else if(header.pixel_size == 16) format = Image::FORMAT_RG8;
		else {
			Log::error("ImageFileTGA::read_header(): unsupported pixel size %d in \"%s\" file\n",header.pixel_size,file.getName());
			return 0;
		}
	}
	// color format
	else if(header.image_type == 2 || header.image_type == 10) {
		if(header.pixel_size == 24) format = Image::FORMAT_RGB8;
		else if(header.pixel_size == 32) format = Image::FORMAT_RGBA8;
		else {
			Log::error("ImageFileTGA::read_header(): unsupported pixel size %d in \"%s\" file\n",header.pixel_size,file.getName());
			return 0;
		}
	}
	else {
		Log::error("ImageFileTGA::read_header(): unsupported type %d in \"%s\" file\n",header.image_type,file.getName());
		return 0;
	}
	
	return 1;
}

/*
 */
void ImageFileTGA::read_data(unsigned char *data,const File &file,size_t size,int pixel_size,int compression) {
	
	// raw image
	if(compression == 0) {
		file.read(data,pixel_size,size);
	}
	// run-length encoded image
	else {
		unsigned char *d = data;
		for(size_t i = 0; i < size;) {
			unsigned char rep = 0;
			if(file.read(&rep,sizeof(unsigned char),1) != 1) break;
			if(rep & 0x80) {
				rep ^= 0x80;
				file.read(d,pixel_size,1);
				d += pixel_size;
				for(int j = 0; j < rep * pixel_size; j++) {
					*d = *(d - pixel_size);
					d++;
				}
			} else {
				file.read(d,pixel_size,rep + 1);
				d += pixel_size * (rep + 1);
			}
			i += rep + 1;
		}
	}
}

/*
 */
int ImageFileTGA::info(Image &image,const char *name) {
	
	File file;
	if(file.open(name,"rb") == 0) {
		Log::error("ImageFileTGA::info(): can't open \"%s\" file\n",name);
		return 0;
	}
	
	// read header
	int format;
	Header header;
	if(read_header(header,format,file) == 0) {
		file.close();
		return 0;
	}

	// create image
	image.create2D(header.width,header.height,format,1,0,0);
	
	file.close();
	
	return 1;
}

/*
 */
int ImageFileTGA::load(Image &image,const char *name) {
	
	File file;
	if(file.open(name,"rb") == 0) {
		Log::error("ImageFileTGA::load(): can't open \"%s\" file\n",name);
		return 0;
	}
	
	// read header
	int format;
	Header header;
	if(read_header(header,format,file) == 0) {
		file.close();
		return 0;
	}
	file.seekCur(header.id_length);
	
	// create image
	image.create2D(header.width,header.height,format,1,0);
	
	// indexed image
	if(header.image_type == 1 || header.image_type == 9) {
		
		size_t size = header.colormap_length * header.colormap_size / 8;
		unsigned char *colormap = new unsigned char[size];
		file.read(colormap,sizeof(unsigned char),size);
		
		size = header.width * header.height;
		unsigned char *buf = new unsigned char[size];
		read_data(buf,file,size,1,(header.image_type == 9));
		
		unsigned char *data = image.getPixels2D();
		
		for(size_t i = 0; i < size; i++) {
			if(header.colormap_size == 24) {
				data[i * 3 + 0] = colormap[buf[i] * 3 + 2];
				data[i * 3 + 1] = colormap[buf[i] * 3 + 1];
				data[i * 3 + 2] = colormap[buf[i] * 3 + 0];
			} else if(header.colormap_size == 32) {
				data[i * 4 + 0] = colormap[buf[i] * 4 + 3];
				data[i * 4 + 1] = colormap[buf[i] * 4 + 2];
				data[i * 4 + 2] = colormap[buf[i] * 4 + 1];
				data[i * 4 + 3] = colormap[buf[i] * 4 + 0];
			}
		}
		
		delete [] colormap;
		delete [] buf;
	}
	// grayscale image
	else if(header.image_type == 3 || header.image_type == 11) {
		
		size_t size = header.width * header.height;
		int pixel_size = header.pixel_size / 8;
		read_data(image.getPixels2D(),file,size,pixel_size,(header.image_type == 11));
	}
	// color format
	else if(header.image_type == 2 || header.image_type == 10) {
		
		size_t size = header.width * header.height;
		int pixel_size = header.pixel_size / 8;
		read_data(image.getPixels2D(),file,size,pixel_size,(header.image_type == 10));
		
		image.swap(0,2);
	}
	else {
		Log::error("ImageFileTGA::load(): unsupported type %d in \"%s\" file\n",header.image_type,name);
		file.close();
		return 0;
	}
	
	// flip image vertically
	if((header.attributes & 0x20) == 0) {
		image.flipY();
	}
	
	file.close();
	
	return 1;
}

/*
 */
int ImageFileTGA::save(const Image &image,const char *name) {
	
	if(image.getType() != Image::IMAGE_2D) {
		Log::error("ImageFileTGA::save(): bad image type %s\n",image.getTypeName());
		return 0;
	}
	
	// create tga header
	Header header;
	memset(&header,0,sizeof(header));
	header.width = image.getWidth();
	header.height = image.getHeight();
	
	// select format
	if(image.getFormat() == Image::FORMAT_R8) {
		header.image_type = 3;
		header.pixel_size = 8;
		header.attributes = 1 << 5;
	} else if(image.getFormat() == Image::FORMAT_RG8) {
		header.image_type = 3;
		header.pixel_size = 16;
		header.attributes = 1 << 5;
	} else if(image.getFormat() == Image::FORMAT_RGB8) {
		header.image_type = 2;
		header.pixel_size = 24;
		header.attributes = 1 << 5;
	} else if(image.getFormat() == Image::FORMAT_RGBA8) {
		header.image_type = 2;
		header.pixel_size = 32;
		header.attributes = (1 << 5) | (1 << 3);
	} else {
		Log::error("ImageFileTGA::save(): can't save %s format into the \"%s\" file\n",image.getFormatName(),name);
		return 0;
	}
	
	File file;
	if(file.open(name,"wb") == 0) {
		Log::error("ImageFileTGA::save(): can't create \"%s\" file\n",name);
		return 0;
	}
	
	// write header
	file.writeUChar(header.id_length);
	file.writeUChar(header.colormap_type);
	file.writeUChar(header.image_type);
	file.writeUShort(header.colormap_index);
	file.writeUShort(header.colormap_length);
	file.writeUChar(header.colormap_size);
	file.writeUShort(header.x_orign);
	file.writeUShort(header.y_orign);
	file.writeUShort(header.width);
	file.writeUShort(header.height);
	file.writeUChar(header.pixel_size);
	file.writeUChar(header.attributes);
	
	// write image
	if(image.getFormat() == Image::FORMAT_R8) {
		file.write(image.getPixels2D(),sizeof(unsigned char),image.getWidth() * image.getHeight());
	}
	else if(image.getFormat() == Image::FORMAT_RG8) {
		file.write(image.getPixels2D(),sizeof(unsigned char),image.getWidth() * image.getHeight() * 2);
	}
	else if(image.getFormat() == Image::FORMAT_RGB8) {
		size_t size = image.getWidth() * image.getHeight() * 3;
		unsigned char *buf = new unsigned char[size];
		const unsigned char *data = image.getPixels2D();
		for(size_t i = 0; i < size; i += 3) {
			buf[i + 0] = data[i + 2];
			buf[i + 1] = data[i + 1];
			buf[i + 2] = data[i + 0];
		}
		file.write(buf,sizeof(unsigned char),size);
		delete [] buf;
	}
	else if(image.getFormat() == Image::FORMAT_RGBA8) {
		size_t size = image.getWidth() * image.getHeight() * 4;
		unsigned char *buf = new unsigned char[size];
		const unsigned char *data = image.getPixels2D();
		for(size_t i = 0; i < size; i += 4) {
			buf[i + 0] = data[i + 2];
			buf[i + 1] = data[i + 1];
			buf[i + 2] = data[i + 0];
			buf[i + 3] = data[i + 3];
		}
		file.write(buf,sizeof(unsigned char),size);
		delete [] buf;
	}
	
	file.close();
	
	return 1;
}

#endif 

